﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using System.Diagnostics;

namespace HeresyManager.Comunication
{
    public class ChooseOne : Comunicator
    {
        public String Question { get; private set; }

        public String[] Posebilitys { get; private set; }

        public int SelectedIndex { get; set; }

        internal ChooseOne(String question, params String[] t)
        {
            SelectedIndex = -1;
            Posebilitys = t;
            Question = question;
        }
    }
    internal class ChooseOne<T> : ChooseOne
    {
        private Tuple<string, T>[] values;

        private int min;
        private int max;

        public T SelectedValue
        {
            get
            {
                return SelectedIndex == -1 ? default(T) : values[SelectedIndex].Item2;
            }
        }



        internal ChooseOne(String question, params Tuple<String, T>[] values)
            : base(question, (from t in values select t.Item1).ToArray())
        {
            this.values = values;
            if (IsRandomSupported)
            {
                min = values.Min(t => (t.Item2 as IMinMaxRole).MinRole);
                max = values.Max(t => (t.Item2 as IMinMaxRole).MaxRole);

#if DEBUG
                for (int i = min; i <= max; i++)
                {
                    Debug.Assert(values.Count(t => i >= (t.Item2 as IMinMaxRole).MinRole && i <= (t.Item2 as IMinMaxRole).MaxRole) == 1);
                }
#endif
            }
        }

        public ChooseOne(String question, params  T[] values)
            : this(question, (from t in values select new Tuple<String, T>(t.ToString(), t)).ToArray())
        {

        }

        public override bool IsRandomSupported
        {
            get
            {
                return values.Length != 0 && values[0].Item2 is IMinMaxRole;
            }
        }

        public override IDice Dice
        {
            get
            {
                if (!IsRandomSupported)
                    return base.Dice;
                return new Dice(max - min + 1);
            }
        }

        public override void Random()
        {
            int i = Dice.Roll();
            var selection = values.First(t => i >= (t.Item2 as IMinMaxRole).MinRole && i <= (t.Item2 as IMinMaxRole).MaxRole);
            SelectedIndex = Array.IndexOf(values, selection);
        }
    }

    internal class ChoseTalentFromType : ChooseOne<Talent>
    {
        public ChoseTalentFromType(String question, Character c, Type type)
            : base(question, ObjectsFromType(type, c))
        {
        }

        private static Talent[] ObjectsFromType(Type searchedType, Character c)
        {
            List<Talent> list = new List<Talent>();
            if (!searchedType.IsAbstract)
            {
                var con = searchedType.GetConstructor(new Type[0]);
                var obj = con.Invoke(new Object[0]);
                var talent = (Talent)obj;
                if (talent.IsPreconditionSattisfied(c))
                    list.Add(talent);
            }
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                foreach (var type in assembly.GetTypes())
                {
                    if (type.IsSubclassOf(searchedType) && !type.IsAbstract)
                    {
                        var con = type.GetConstructor(new Type[0]);
                        var obj = con.Invoke(new Object[0]);
                        var talent = (Talent)obj;
                        if (talent.IsPreconditionSattisfied(c))
                            list.Add(talent);
                    }
                }
            }
            return list.ToArray();
        }

    }

    internal class ChoseSkilFromType : ChooseOne<Skill>
    {
        public ChoseSkilFromType(String question, Character c, Type type, Skill.SkillLevel level)
            : base(question, ObjectsFromType(type, c, level))
        {
        }

        private static Skill[] ObjectsFromType(Type searchedType, Character c, Skill.SkillLevel level)
        {
            List<Skill> list = new List<Skill>();
            if (!searchedType.IsAbstract)
            {
                var con = searchedType.GetConstructor(new Type[] { typeof(Skill.SkillLevel) });
                var obj = con.Invoke(new Object[] { level });
                var talent = (Skill)obj;
                if (talent.IsPreconditionSattisfied(c))
                    list.Add(talent);
            }
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                foreach (var type in assembly.GetTypes())
                {
                    if (type.IsSubclassOf(searchedType) && !type.IsAbstract)
                    {
                        var con = type.GetConstructor(new Type[] { typeof(Skill.SkillLevel) });
                        var obj = con.Invoke(new Object[] { level });
                        var talent = (Skill)obj;
                        if (talent.IsPreconditionSattisfied(c))
                            list.Add(talent);
                    }
                }
            }
            return list.ToArray();
        }

    }
}
